package com.gxd.redis.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.lang.reflect.Method;

/**
 * @Author:gxd
 * @Description:
 * @Date: 18:32 2018/1/8
 * @Modified By:
 */
@SuppressWarnings("SpringJavaAutowiringInspection") //加这个注解让IDE 不报: Could not autowire
@Configuration
@EnableCaching//启用缓存的意思
public class CacheConfig extends CachingConfigurerSupport {
    private static final Logger logger = LoggerFactory.getLogger(CacheConfig.class);
    @Autowired
    private RedisClusterProperties redisClusterProperties;
    @Autowired
    private RedisSingleProperties redisSingleProperties;

    /**
     * 自定义key. 这个可以不用
     * 此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一样，key也会不一样。
     */
    @Bean
    public KeyGenerator customKeyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                //sb.append(target.getClass().getSimpleName());
                //sb.append(method.getName());
                for (Object o : params) {
                    sb.append(":").append(o.toString());
                }
                return redisClusterProperties.getBizKey()+":"+method.getName()+sb.toString();
            }
        };
    }

    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
       //设置缓存过期时间
       rcm.setDefaultExpiration(redisClusterProperties.getExpireTime());//秒
        return rcm;
    }


    @Bean(name="clusterRedisConnection")
    @ConditionalOnProperty(name = "spring.redis.cluster.enable", havingValue = "true")
    public RedisConnectionFactory getClusterConnection() {
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisClusterProperties.getNodes());
        redisClusterConfiguration.setMaxRedirects(redisClusterProperties.getMaxRedirects());
        logger.debug("load redis cluster success {} ", redisClusterProperties.getNodes().toString());
        return new JedisConnectionFactory(redisClusterConfiguration);
    }


    @Bean
    @ConfigurationProperties(prefix="spring.redis")
    @ConditionalOnProperty(name = "spring.redis.single.enable", havingValue = "true")
    public JedisPoolConfig getRedisConfig(){
        JedisPoolConfig config = new JedisPoolConfig();
        return config;
    }

    @Bean(name="singleRedisConnection")
    @ConditionalOnProperty(name = "spring.redis.single.enable", havingValue = "true")
    public JedisConnectionFactory redisConnectionFactory(){
        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
        redisConnectionFactory.setHostName(redisSingleProperties.getAddress());
        redisConnectionFactory.setPort(redisSingleProperties.getPort());
        redisConnectionFactory.setPassword(redisSingleProperties.getPassword());
        return redisConnectionFactory;
    }

    @Primary
    @Bean(name = "sessionJedisConnectionFactory")
    @ConditionalOnProperty(name = "spring.redis.single.enable", havingValue = "true")
    public RedisConnectionFactory sessionJedisConnectionFactory() {
        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
        redisConnectionFactory.setHostName(redisSingleProperties.getAddress());
        redisConnectionFactory.setPort(redisSingleProperties.getPort());
        redisConnectionFactory.setPassword(redisSingleProperties.getPassword());
        return redisConnectionFactory;
    }
    /**
     * RedisTemplate配置
     * 设置数据存入 redis 的序列化方式
     * Jackson序列化  json占用的内存最小 Jdk序列化   JdkSerializationRedisSerializer是最高效的
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        logger.debug("RedisTemplate 初始化成功......");
        return template;
    }
}
